查看原文
其他

一文搞懂select语句在MySQL中的执行流程!

冰河 冰河技术 2022-09-10

大家好,我是冰河~~

MySQL作为互联网行业使用最多的关系型数据库之一,与其免费、开源的特性是密不可分的。然而,很多小伙伴工作了很多年,只知道使用MySQL进行CRUD操作,这也导致很多小伙伴工作多年后,想跳槽进入大厂,却在面试的时候屡屡碰壁。

问个简单的问题:select语句是如何在MySQL中执行的? 这也是很多面试官喜欢问的问题,如果你连这个简单的问题都不能回答的话,那就要好好规划下自己的职业生涯了。

好了,今天我们就一起来聊聊select语句是如何在MySQL中执行的。文章的主要内容如下。

频繁使用的select语句

为了更好地贯穿全文,这里先来列举一个最简单的select查询语句,例如:查询user表中id为1001的用户信息,使用下面的SQL语句进行查询。

select * from user where user_id = 1001;

当我们在MySQL的命令行中输入上述SQL语句时,这条SQL语句到底在MySQL中是如何执行的呢?接下来,我们就以这条SQL语句为例,说说select语句是如何在MySQL中执行的。

MySQL逻辑架构

在介绍select语句在MySQL中的执行流程之前,我们先来看看MySQL的逻辑架构,因为任何SQL语句的执行都离不开MySQL逻辑架构的支撑。也就是说,SQL语句在MySQL中的执行流程与MySQL的逻辑架构是密不可分的。

在上图中,我们简单的画了下MySQL的逻辑架构图,并且给出了逻辑分层和每层中各部分的功能。从逻辑上,我们可以将MySQL粗略地分成三层:Server层、存储引擎层和系统文件层,而Server层中又可以分成网络连接层(连接器)和数据服务层(Server层)。

Server层中包含了连接器、查询缓存、分析器、优化器和执行器等MySQL的核心组成部分,另外,在Server层中还包含了所有的内置函数(比如:日期时间函数、加解密函数、聚合函数、数学函数等),存储引擎、触发器、视图等等。

存储引擎层主要负责和系统文件层进行交互,存储引擎层本身是插件式的架构设计,支持InnoDB、MyISAM、Archive、Memory等存储引擎。在MySQL 5.5.5及以后的版本中,MySQL的默认存储引擎是InnoDB。

系统文件层主要负责存储实际的数据,将数据以文件的形式存储到服务器的磁盘上。

接下来,我们就来说说一条select语句在MySQL的逻辑架构的每一部分到底是如何执行的。

连接器是如何授权的?

首先,我们先来看看在服务器命令行输入连接MySQL的命令时,MySQL的连接器是如何进行验证的。比如,我们在服务器的命令行输入了如下命令。

mysql -ubinghe -p

执行“回车”后,输入binghe账户的密码,与MySQL进行连接。此时,连接的过程需要完成经典的TCP握手操作(有关TCP的握手相关的知识,小伙伴们可以参考《【面经】面试官:讲讲七层网络模型与TCP三次握手与四次断开?》)。之后,连接器就开始认证连接的身份是否合法,最直接的就是验证用户名和密码是否正确。

如果用户名或者密码错误,MySQL会提示 Access denied for user。如果用户名和密码正确,则连接器会到MySQL的权限表中查询当前连接拥有的权限。查询到权限之后,只要这个连接没有断开,则这个连接涉及到的权限操作都会依赖此时查询到的权限。

换句话说,一个用户登录MySQL并成功连接MySQL后,哪怕是管理员对当前用户的权限进行了修改操作,此时只要这个用户没有断开MySQL的连接,就不会受到管理修改权限的影响。管理员修改权限后,只有对新建的连接起作用。

如果客户端连接MySQL后,长时间没有执行任何操作,则连接器会自动断开与这个客户端的连接。具体多长时间断开是由MySQL的参数wait_timeout控制的,这个值默认是8小时。我们可以根据实际业务需要,自行调整这个参数的值,以使MySQL能够满足我们的实际业务场景。

由于客户端与MySQL的连接是比较复杂的,这个过程也是比较耗时的,它会涉及TCP的握手操作,还会查询当前连接的权限信息等。往往在实际的工作过程中,我们会使用数据库连接池的方式,将数据库的连接缓存起来,这就意味着我们是使用长连接与MySQL进行交互的。

但是使用长连接连接MySQL也会有一个问题:那就是有时候会发现MySQL占用的内存涨得特别快,这是因为MySQL在执行的过程中,使用的临时内存是在连接对象里面进行管理的。这些占用的资源只有在连接断开的时候,才会被释放。如果连接长时间不释放,就会出现大量的临时内存占用内存空间。如果时间久了,可能会导致占用过多的内存,从而被操作系统“消灭”了,给人的感觉就是MySQL意外重启了。

我们可以使用如下的方案来解决这个问题:

  • 定期或者执行过一个比较占内存的查询操作后,断开连接,以后再重新建立和MySQL的连接。
  • 如果使用MySQL 5.7或更新的MySQL版本,可以通过执行mysql_reset_connection重新初始化MySQL的资源。重新初始化的过程不会重新连接MySQL,也不会重新做权限的验证操作。

查询缓存的作用是什么?

登录MySQL后,客户端就会与MySQL建立连接,此时执行select语句时,首先会到查询缓存中查询是否执行过当前select语句。如果之前执行过相应的select语句,则执行过的select语句和查询结果会以key-value的形式存放在查询缓存中,其中,key是查询语句,value是查询的结果数据。

如果在查询缓存中没有找到相应的数据,则会继续执行后续的查询阶段。执行完成后,会将结果缓存到查询缓存中。后续的查询如果命中缓存,则直接返回查询缓存中的数据,性能还是挺高的。

但是,大多数时候我不太建议小伙伴们开启查询缓存,为啥?原因很简单:查询缓存失效的频率是非常频繁的,只要对一个表进行更新操作,则这张表上所有的查询缓存都会被清空。 而且在MySQL 8.0中,直接删除了查询缓存的功能(冰河在看MySQL源码时,也证明了这一点)。

分析器对select语句做了什么?

分析器主要是对select语句进行 词法分析和语法分析 操作。

如果select语句没有命中缓存,则首先会由分析器对其进行“词法分析”操作,此时,MySQL会识别select语句中的每个字符串代表什么含义。

例如,MySQL会通过"select"关键字识别出这是一个查询语句,也会把"user"识别为"数据表名user",把"id"识别成"字段名id"。接下来,就要进行“语法分析了”,根据语法规则,判断select语句是否满足MySQL的语法。如果判断出输入的SQL语句不满足语法规则,则MySQL会提示相应的错误信息。

优化器是如何优化select语句的?

对select语句进行了词法分析和语法分析后,还要经过优化器的优化处理才能执行。比如,我们的select语句中如果使用了多个索引,则优化器会决定使用哪个索引来查询数据;再比如,在select语句中,有多表关联的操作,优化器会决定各表的连接顺序,数据表的连接顺序不同,对于执行的效率会大不相同,优化器往往会选择使用查询效率高的连接顺序。

如果select语句经过优化器的优化之后,就会进入执行阶段了。

执行器如何执行select语句?

进入执行阶段的select语句,首先,执行器会对当前连接进行权限检查,最直接的方式就是检查当前连接是否对数据表user具有查询权限。如果当前连接对数据表user没有查询权限,就会返回没有权限的错误。例如,会返回如下错误。

ERROR 1142 (42000): SELECT command denied to user 'binghe'@'localhost' for table 'user'

如果当前连接具有对数据表user的查询权限,则会继续执行。首先会进行打开数据表的操作,此时优化器会根据创建表时使用的存储引擎,使用相应存储引擎的接口执行查询操作。这里,我们举一个例子:

假设,我们在id字段上没有建立索引,执行器执行的流程大致如下所示。

(1)通过存储引擎读取数据表user的第一行数据,判断当前行的id值是否等于1001,如果不等于1001,则继续读取下一行数据;如果等于1001,则将当前行放入结果集中。

(2)继续通过存储引擎读取下一行数据,执行与(1)相同的逻辑判断,直到处理完user表中的所有数据。

(3)处理完所有的数据后,执行器就会将结果集中的数据返回给客户端。

如果在id字段上有索引的话,执行的整体逻辑与id字段上没有索引大体一致。

如果开启了慢查询的话,执行select语句时,会在慢查询日志中输出一个rows_examined字段,这个字段表示select语句在执行的过程中扫描了数据表中的多少行数据。不过在有些场景下,执行器调用一次,存储引擎内部会会扫描多行,这就导致存储引擎扫描的行数与rows_examined字段标识的行数并不完全相同。

好了,今天就到这儿吧,我是冰河,大家有啥问题可以在下方留言,也可以加我微信:sun_shine_lyz,我拉你进群,一起交流技术,一起进阶,一起牛逼~~

冰河原创PDF

关注 冰河技术 微信公众号:

回复 “并发编程” 领取《深入理解高并发编程(第1版)》PDF文档。

回复 “并发源码” 领取《并发编程核心知识(源码分析篇 第1版)》PDF文档。

回复 “我要进大厂” 领取《我要进大厂系列之面试圣经(第1版)》PDF文档。

回复 ”限流“ 领取《亿级流量下的分布式解决方案》PDF文档。

回复 “设计模式” 领取《深入浅出Java23种设计模式》PDF文档。

回复 “Java8新特性” 领取 《Java8新特性教程》PDF文档。

回复 “分布式存储” 领取《跟冰河学习分布式存储技术》 PDF文档。

回复 “Nginx” 领取《跟冰河学习Nginx技术》PDF文档。

回复 “互联网工程” 领取《跟冰河学习互联网工程技术》PDF文档。

写在最后

如果你觉得冰河写的还不错,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习高并发、分布式、微服务、大数据、互联网和云原生技术,「 冰河技术 」微信公众号更新了大量技术专题,每一篇技术文章干货满满!不少读者已经通过阅读「 冰河技术 」微信公众号文章,成功跳槽到大厂;也有不少读者实现了技术上的飞跃,成为公司的技术骨干!如果你也想像他们一样提升自己的能力,实现技术能力的飞跃,进大厂,升职加薪,那就关注「 冰河技术 」微信公众号吧,每天更新超硬核技术干货,让你对如何提升技术能力不再迷茫!


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存